package top.kikt.book.core

import okhttp3.HttpUrl.Companion.toHttpUrl
import top.kikt.book.core.base.BookGetter
import top.kikt.book.core.base.IBookHandler
import top.kikt.book.core.base.ILogger
import top.kikt.book.core.config.AppConfig
import top.kikt.book.core.handlers.*
import top.kikt.book.util.HttpUtils
import java.io.File

class BookCatcher(private val appConfig: AppConfig) : ILogger {

    @Suppress("unused")
    companion object {
        private val bookHandlers = arrayListOf<IBookHandler>(
            X810book(),
            Ddxs(),
            `3UXiaoShuo`(),
            BookXuan(),
            Biquw(),
            QuDuShu(),
            `800Book`(),
            `79Wx`(),
            `31Xs`(),
            YouYiYan(),
            Biqugse(),
            `23Usp`(),
            Qqduu(),
            Ibiquge(),
            Sdlchxwz(),
            BiQuZW(),
            `7yyq`(),
            Ygshu(),
            Picdg(),
            `93mc`(),
            PinShu(),
            Lidapoly(),
            Luoqiuzw(),
            Jjxinshu(),
            `23Qb`(),
            Bnn2(),
        )

        fun getSupportBookHost(): List<String> {
            return bookHandlers.map { it.host }
        }

        private fun getSupportHandlerList(): List<IBookHandler> {
            return bookHandlers.filter(IBookHandler::isSupported)
        }

        fun registerBookHandler(bookHandler: IBookHandler) {
            bookHandlers.add(bookHandler)
        }

        fun unregisterBookHandler(bookHandler: IBookHandler) {
            bookHandlers.remove(bookHandler)
        }

        @Suppress("MemberVisibilityCanBePrivate")
        fun findBookHandlerByHost(host: String): IBookHandler? {
            return getSupportHandlerList().firstOrNull {
                it.host == host
            }
        }

        fun findBookHandlerByUrl(url: String): IBookHandler? {
            val httpUrl = url.toHttpUrl()
            return findBookHandlerByHost(httpUrl.host)
        }
    }

    class Handler(val url: String, private val config: AppConfig) : ILogger {
        fun catchBook(): List<File> {
            try {
                val book = bookGetter.parse() ?: throw RuntimeException("获取书籍失败")
                logger.info("解析 ${book.metaEntity.name} 完成, 准备解析章节")

                if (config.output) {
                    return bookGetter.writeFile(bookHandler, book, config)
                }
                return emptyList()
            } catch (e: Exception) {
                e.printStackTrace()
                throw RuntimeException("获取书籍失败，当前 handler 类型: ${bookGetter.bookHandler.javaClass.name}")
            }
        }

        fun tryStopCatch() {
            bookGetter.tryStop()
        }

        private val bookGetter: BookGetter
        private val bookHandler: IBookHandler

        init {
            val thread = config.thread
            config.cookies?.let {
                HttpUtils.addGlobalHeader("Cookie", it)
            }

            var iBookHandler: IBookHandler? = null
            for (handler in bookHandlers) {
                if (handler.guestType(url)) {
                    iBookHandler = handler
                    break
                }
            }

            if (iBookHandler == null) {
//                throw IllegalStateException(
//                    "没有找到对应的书籍获取器, 支持的域名: \n${
//                        bookHandlers.joinToString("\n") { it.hosts.joinToString("\n") }
//                    }" + "\n当前的 url: $url"
//                )
                logger.info("没有找到对应的书籍获取器，尝试使用默认的 DefaultBookHandler")
                iBookHandler = DefaultBookHandler()
            }

            if (!iBookHandler.isSupported()) {
                throw IllegalStateException("对应的域名暂不支持")
            }

            iBookHandler.currentHost = url.toHttpUrl().host

            bookGetter = BookGetter(url, iBookHandler, thread)
            bookHandler = iBookHandler
        }
    }

    private var handlerMap = HashMap<String, Handler>()

    init {
        run {
            val url = appConfig.url
            if (url != null) {
                handlerMap[url] = Handler(url, appConfig)
            }
        }
        run {
            val urls = appConfig.urls
            if (urls != null) {
                for (url in urls) {
                    if (url.isNullOrEmpty()) {
                        continue
                    }
                    handlerMap[url] = Handler(url, appConfig)
                }
            }
        }
    }

    fun catchBook(): List<File> {
        val result = ArrayList<File>()

        for (handlers in handlerMap.values) {
            val files = handlers.catchBook()
            result.addAll(files)
        }

        return result
    }

    @Suppress("unused")
    fun tryStopCatch() {
        handlerMap.values.forEach {
            it.tryStopCatch()
        }
    }
}